#!/usr/bin/env julia
"""
Julia GSI Diagnostic File Checker

This script provides detailed analysis of Julia GSI diagnostic files,
similar to the Fortran GSI diagnostic checking tools.

Usage:
    julia check_diagnostics.jl [OPTIONS]

Options:
    --diag-dir DIR          Directory containing diagnostic files (default: ../results/diagnostics)
    --compare-fortran       Compare with Fortran GSI output
    --fortran-dir DIR       Fortran GSI diagnostic directory
    --verbose               Show detailed output
    --help                  Show this help message
"""

using Printf
using Dates
using Statistics

# Parse command line arguments
function parse_args(args)
    config = Dict(
        :diag_dir => joinpath(@__DIR__, "..", "results", "diagnostics"),
        :fortran_dir => "/home/linden/comGSI/run/job/basic",
        :compare_fortran => false,
        :verbose => false
    )

    i = 1
    while i <= length(args)
        arg = args[i]
        if arg == "--diag-dir" && i < length(args)
            config[:diag_dir] = args[i+1]
            i += 2
        elseif arg == "--fortran-dir" && i < length(args)
            config[:fortran_dir] = args[i+1]
            i += 2
        elseif arg == "--compare-fortran"
            config[:compare_fortran] = true
            i += 1
        elseif arg == "--verbose"
            config[:verbose] = true
            i += 1
        elseif arg == "--help"
            println(__doc__)
            exit(0)
        else
            @warn "Unknown argument: $arg"
            i += 1
        end
    end

    return config
end

# Check if file exists and get info
function check_file(filepath::String; verbose=false)
    if !isfile(filepath)
        return (exists=false, size=0, readable=false)
    end

    size = filesize(filepath)
    readable = isreadable(filepath)

    if verbose
        println("  File: $(basename(filepath))")
        println("    Size: $(size) bytes ($(round(size/1024, digits=2)) KB)")
        println("    Readable: $(readable)")
    end

    return (exists=true, size=size, readable=readable)
end

# Read and parse text diagnostic file
function parse_text_diagnostic(filepath::String)
    if !isfile(filepath)
        return nothing
    end

    content = read(filepath, String)
    lines = split(content, '\n')

    stats = Dict{String,Any}()

    for line in lines
        # Parse observation counts
        if occursin("count", lowercase(line)) || occursin("observations", lowercase(line))
            # Extract numbers
            numbers = [parse(Int, m.match) for m in eachmatch(r"\d+", line)]
            if !isempty(numbers)
                stats["count"] = numbers[1]
            end
        end

        # Parse RMS values
        if occursin("rms", lowercase(line))
            numbers = [parse(Float64, m.match) for m in eachmatch(r"\d+\.\d+", line)]
            if !isempty(numbers)
                stats["rms"] = numbers[1]
            end
        end

        # Parse bias values
        if occursin("bias", lowercase(line))
            numbers = [tryparse(Float64, m.match) for m in eachmatch(r"-?\d+\.\d+", line)]
            numbers = filter(!isnothing, numbers)
            if !isempty(numbers)
                stats["bias"] = numbers[1]
            end
        end
    end

    return stats
end

# Analyze binary diagnostic file
function analyze_binary_diagnostic(filepath::String; verbose=false)
    if !isfile(filepath)
        @warn "File not found: $filepath"
        return nothing
    end

    info = Dict{String,Any}()

    try
        open(filepath, "r") do io
            # Read first few bytes to check format
            header_bytes = read(io, min(256, filesize(filepath)))

            info["file_size"] = filesize(filepath)
            info["first_bytes"] = header_bytes[1:min(64, length(header_bytes))]

            # Try to detect record markers (Fortran binary format)
            seek(io, 0)
            if filesize(filepath) >= 4
                first_marker = read(io, Int32)
                info["first_record_marker"] = first_marker

                if verbose
                    println("  First record marker: $first_marker bytes")
                end
            end

            # Estimate number of records
            if haskey(info, "first_record_marker") && info["first_record_marker"] > 0
                marker = info["first_record_marker"]
                # Each record: 4 (open marker) + data + 4 (close marker)
                record_size = 4 + marker + 4
                n_records = div(filesize(filepath), record_size)
                info["estimated_records"] = n_records

                if verbose
                    println("  Estimated records: $n_records")
                    println("  Record size: ~$record_size bytes")
                end
            end
        end
    catch e
        @warn "Error reading binary file: $e"
        return nothing
    end

    return info
end

# Main checking function
function check_diagnostics(config)
    println("="^80)
    println("Julia GSI Diagnostic File Checker")
    println("="^80)
    println()

    diag_dir = config[:diag_dir]
    verbose = config[:verbose]

    println("Diagnostic directory: $diag_dir")
    println("Timestamp: $(Dates.format(now(), "yyyy-mm-dd HH:MM:SS"))")
    println()

    if !isdir(diag_dir)
        @error "Diagnostic directory not found: $diag_dir"
        return false
    end

    # Expected diagnostic files
    expected_files = [
        "diag_obs_setup_anl.2018081212",
        "diag_obs_setup_ges.ensmean",
        "fort.201",
        "fort.202",
        "fort.203",
        "fort.204",
        "convergence_diagnostics.txt",
        "innovation_diagnostics.txt",
        "qc_diagnostics.txt"
    ]

    println("="^80)
    println("Checking Expected Diagnostic Files")
    println("="^80)
    println()

    found_count = 0
    total_size = 0

    for filename in expected_files
        filepath = joinpath(diag_dir, filename)
        info = check_file(filepath, verbose=verbose)

        if info.exists
            found_count += 1
            total_size += info.size
            status = info.readable ? "✓" : "⚠"
            @printf "%s %-40s %12d bytes\n" status filename info.size
        else
            @printf "✗ %-40s %12s\n" filename "MISSING"
        end
    end

    println()
    println("Summary: $found_count/$(length(expected_files)) files found")
    println("Total size: $total_size bytes ($(round(total_size/1024/1024, digits=2)) MB)")
    println()

    # Analyze binary diagnostic files
    println("="^80)
    println("Analyzing Binary Diagnostic Files")
    println("="^80)
    println()

    for filename in ["diag_obs_setup_anl.2018081212", "diag_obs_setup_ges.ensmean"]
        filepath = joinpath(diag_dir, filename)
        if isfile(filepath)
            println("File: $filename")
            info = analyze_binary_diagnostic(filepath, verbose=verbose)
            if info !== nothing
                @printf "  Size: %d bytes\n" info["file_size"]
                if haskey(info, "estimated_records")
                    @printf "  Estimated records: %d\n" info["estimated_records"]
                end
            end
            println()
        end
    end

    # Parse text diagnostic files
    println("="^80)
    println("Text Diagnostic File Contents")
    println("="^80)
    println()

    for filename in ["fort.201", "fort.202", "innovation_diagnostics.txt", "qc_diagnostics.txt"]
        filepath = joinpath(diag_dir, filename)
        if isfile(filepath)
            println("─"^80)
            println("File: $filename")
            println("─"^80)

            # Read and display first 30 lines
            lines = readlines(filepath)
            n_display = min(30, length(lines))
            for line in lines[1:n_display]
                println("  ", line)
            end

            if length(lines) > n_display
                println("  ... ($(length(lines) - n_display) more lines)")
            end
            println()
        end
    end

    # Compare with Fortran if requested
    if config[:compare_fortran]
        println("="^80)
        println("Comparison with Fortran GSI")
        println("="^80)
        println()

        fortran_dir = config[:fortran_dir]

        if !isdir(fortran_dir)
            @warn "Fortran diagnostic directory not found: $fortran_dir"
        else
            println("Fortran directory: $fortran_dir")
            println()

            @printf "%-40s %15s %15s %15s\n" "File" "Fortran (bytes)" "Julia (bytes)" "Difference"
            println("─"^80)

            for filename in ["diag_obs_setup_anl.2018081212", "diag_obs_setup_ges.ensmean"]
                fortran_file = joinpath(fortran_dir, filename)
                julia_file = joinpath(diag_dir, filename)

                if isfile(fortran_file) && isfile(julia_file)
                    f_size = filesize(fortran_file)
                    j_size = filesize(julia_file)
                    diff = j_size - f_size
                    diff_pct = round(100.0 * diff / f_size, digits=2)

                    @printf "%-40s %15d %15d %10d (%+.1f%%)\n" filename f_size j_size diff diff_pct
                elseif isfile(fortran_file)
                    @printf "%-40s %15d %15s %15s\n" filename filesize(fortran_file) "MISSING" "N/A"
                elseif isfile(julia_file)
                    @printf "%-40s %15s %15d %15s\n" filename "MISSING" filesize(julia_file) "N/A"
                else
                    @printf "%-40s %15s %15s %15s\n" filename "MISSING" "MISSING" "N/A"
                end
            end
            println()
        end
    end

    println("="^80)
    println("Check Complete")
    println("="^80)

    return found_count == length(expected_files)
end

# Main entry point
if abspath(PROGRAM_FILE) == @__FILE__
    config = parse_args(ARGS)

    success = check_diagnostics(config)

    if success
        println()
        println("✓ All diagnostic files present and readable")
        exit(0)
    else
        println()
        println("⚠ Some diagnostic files are missing")
        exit(1)
    end
end
